package com.bytz.modules.cms.order.service.impl;

import cn.hutool.core.lang.func.LambdaUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bytz.common.util.RedisUtil;
import com.bytz.modules.cms.domain.util.DecimalFormatUtil;
import com.bytz.modules.cms.domain.util.PriceComputerUtil;
import com.bytz.modules.cms.echop.service.IEChopService;
import com.bytz.modules.cms.order.constant.OrderConstants;
import com.bytz.modules.cms.order.entity.Order;
import com.bytz.modules.cms.order.entity.OrderItem;
import com.bytz.modules.cms.order.mapper.OrderMapper;
import com.bytz.modules.cms.order.model.ContractDocDo;
import com.bytz.modules.cms.order.model.ContractItemDocDo;
import com.bytz.modules.cms.order.service.IOrderContractService;
import com.bytz.modules.cms.order.service.IOrderItemService;
import com.bytz.modules.cms.order.service.IOrderService;
import com.bytz.modules.cms.product.entity.ProductHierarchy;
import com.bytz.modules.cms.product.service.IProductHierarchyService;
import com.bytz.modules.cms.reseller.service.IResellerEndUserService;
import com.bytz.modules.system.entity.SysUser;
import com.bytz.modules.system.entity.SysxLocalUpload;
import com.bytz.modules.system.service.ICommonService;
import com.bytz.modules.system.service.ISysUserService;
import com.bytz.modules.system.util.FileConvertUtil;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.Pictures;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class OrderContractServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderContractService {

    @Autowired
    private IOrderItemService orderItemService;

    @Autowired
    private ICommonService commonService;

    @Autowired
    private IProductHierarchyService hierarchyService;

    @Autowired
    private IResellerEndUserService resellerEndUserService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private IEChopService eChopService;

    @Value("${cms.template-path}")
    private String templatePath;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private IOrderService orderService;

    @Override
    public String generateContract(String orderId) throws Exception {
        return generateContract(getById(orderId), orderItemService.getByOrderId(orderId));
    }

    @Override
    public String generateContract(Order order, List<OrderItem> items) throws Exception {

        Configure configure = Configure.builder().setValidErrorHandler(new Configure.ClearHandler()).useSpringEL()
                .bind(LambdaUtil.getFieldName(ContractDocDo::getItems), new LoopRowTableRenderPolicy(true))
                .build();

        ContractDocDo contractDoc = new ContractDocDo();

        contractDoc.setOrder(order);

        Set<String> productIds = items.stream().map(OrderItem::getProductId).collect(Collectors.toSet());
        Map<String, ProductHierarchy> hierarchyMap = hierarchyService.getByProductIds(productIds);

        List<ContractItemDocDo> contractItemDocs = new ArrayList<>();
        for (int i = 0; i < items.size(); i++) {
            ContractItemDocDo contractItemDoc = new ContractItemDocDo();
            OrderItem orderItem = items.get(i);
            contractItemDoc.setSortNumber(String.format("%02d", i + 1));
            contractItemDoc.setProductNumber(orderItem.getProductNumber());
            contractItemDoc.setProductDesc(orderItem.getProductDesc());
            contractItemDoc.setProductNum(orderItem.getProductNum());
            contractItemDoc.setUnit(hierarchyMap.get(orderItem.getProductId()).getUnit());
            BigDecimal totalTaxPrice = orderItem.getTotalTaxPrice();
            BigDecimal includeTaxPrice = PriceComputerUtil.divide(totalTaxPrice, BigDecimal.valueOf(orderItem.getProductNum()));
            BigDecimal noTaxPrice = PriceComputerUtil.divide(includeTaxPrice, BigDecimal.ONE.add(order.getTaxRate()));
            contractItemDoc.setTotalTaxPrice(DecimalFormatUtil.formatMoney(totalTaxPrice));
            contractItemDoc.setIncludeTaxPrice(DecimalFormatUtil.formatMoney(includeTaxPrice));
            contractItemDoc.setNoTaxPrice(DecimalFormatUtil.formatMoney(noTaxPrice));
            contractItemDocs.add(contractItemDoc);
        }
        contractDoc.setItems(contractItemDocs);

        contractDoc.setTaxRate(DecimalFormatUtil.formatPercent(order.getTaxRate()));
        contractDoc.setPrepayRatio(DecimalFormatUtil.formatPercent(order.getPrepayRatio()));
        // 订单交期为天，合同里转成周
        contractDoc.setDeliveryDate((int) Math.ceil((double) order.getDeliveryDate() / 7));
        contractDoc.setTotalPrice(DecimalFormatUtil.formatMoney(order.getTotalPrice()));
        // 销售签名
        SysUser sale = sysUserService.getById(order.getSalesId());
        if (sale.getSignature() != null) {
            SysxLocalUpload saleSignature = commonService.getFile(sale.getSignature());
            contractDoc.setSaleSignature(Pictures.ofLocal(commonService.toFile(saleSignature).getPath()).create());
        }

        try (InputStream resourceAsStream = Files.newInputStream(Paths.get(templatePath + OrderConstants.ContractDoc.TEMPLATE))) {
            XWPFTemplate template = XWPFTemplate.compile(resourceAsStream, configure).render(contractDoc);
            MultipartFile multipartFile = FileConvertUtil.createMultipartFile(template, String.format(OrderConstants.ContractDoc.FILE_NAME, order.getContractNumber()));
            return commonService.uploadLocal(multipartFile, OrderConstants.ContractDoc.BIZ_PATH, true);
        }
    }

    @Override
    public void batchGenerate() {
        List<Order> list = getNeedGenerateContractOrders();
        for (Order order : list) {

            if (redisUtil.get("echop:generating:" + order.getContractNumber()) != null) {
                log.info("生成合同任务被redis锁拦截：" + order.getContractNumber());
                continue;
            }
            redisUtil.set("echop:generating:" + order.getContractNumber(), true, 10, TimeUnit.MINUTES);

            try {
                resellerEndUserService.updateShipToAndEndUser(order);
            } catch (Exception e) {
                log.error("同步shipTo失败，合同号:" + order.getContractNumber(), e);
            }
            try {
                orderService.saveEChopId(order.getId(), null, OrderConstants.OrderStatus.DAI_GAI_ZHANG);
                eChopService.generateContract(order, orderItemService.getByOrderId(order.getId()));
            } catch (Exception e) {
                log.error("合同生成失败，合同号:" + order.getContractNumber(), e);
            }
        }
    }

    /**
     * 查找所有需要生成合同的订单
     */
    private List<Order> getNeedGenerateContractOrders() {
        return lambdaQuery()
                .eq(Order::getStatus, OrderConstants.OrderStatus.SHEN_HE_TONG_GUO)
                .and(wrapper -> wrapper
                        .eq(Order::getEcRequired, OrderConstants.EcRequired.UNNECESSARY)
                        .or()
                        .eq(Order::getEcStatus, OrderConstants.EcStatus.CHECKED))
                .list();
    }

}

